#include "Param.h"
#include <regex>

#define memberof(buf) (sizeof(buf) / sizeof(buf[0]))

static int isLegalFormat(const char *format);

extern const char *helpInfo; // 帮助信息，定义于此文件末尾

static const char *params[] = {
    "-h",
    "-o",
    "-i",
    "-f",
    "-c",
    "-b",
    "--alpha",
    "--chromakey",
};

static const char *formats[] = {
    "rgb332",
    "rgb565",
    "rgb565swap",
    "rgb888",
};

static const char *outfileString[] = {
    "c-array",
    "bin",
};

static const char *imgcfgString[] = {
    "true-color",
    "true-color-alpha",
    "true-color-chromakey",
};

static const char *errorString[] = {
    "",
    "-o can not found a output file name",
    "-i can not found a input file name",
    "-f can not found a legal conver format",
    "please use \"-i\" to appoint a input image file",
    "only support for .bmp .png .jpg/jpeg image file",
};

/**
 * @brief 转换参数解析
 * @param argc 参数个数
 * @param argv 参数集合
 * @param error 保存错误码
 * @retval 解析成功 - 参数结构
 * @retval 解析失败- nullptr
 */
ConverParam *ConverParamDecode(int argc, const char *argv[], int *error)
{
    static ConverParam param;
    int conv_format = -1;

    param.format = 3; // 默认为rgb888格式

    for (int i = 0; i < argc; i++)
    {
        string arg(argv[i]);

        int index = 0;
        for (; index < memberof(params); index++)
        {
            if (arg.compare(params[index]) == 0) // 找到匹配的参数
                break;
        }

        switch (index)
        {
        case 0:
            *error = 0;
            printf("%s\n", helpInfo); // 显示帮助信息
            return nullptr;
        case 1:
            if (i + 1 == argc) // 后面没有参数了
            {
                *error = -1;
                return nullptr;
            }
            param.outFileName = string(argv[++i]); // 保存输出文件名
            break;
        case 2:
            if (i + 1 == argc) // 后面没有参数了
            {
                *error = -2;
                return nullptr;
            }
            param.inputFileName = string(argv[++i]); // 保存输入文件名
            break;
        case 3:
            if (i + 1 == argc || (conv_format = isLegalFormat(argv[++i])) < 0) // 后面没有参数了或非法转换格式
            {
                *error = -3;
                return nullptr;
            }
            param.format = conv_format; // 保存转换格式
            break;
        case 4: // 输出c文件
            param.outFile = 0;
            break;
        case 5: // 输出bin文件
            param.outFile = 1;
            break;
        case 6: // 带alpha通道
            param.imgcfg = 1;
            break;
        case 7: // chorma key参数
            param.imgcfg = 2;
        default:
            break;
        }
    }

    if (param.inputFileName == "") // 未指定输入图像
    {
        *error = -4;
        return nullptr;
    }
    else // 判断文件后缀名是否合法
    {
        int dotPos = param.inputFileName.find_last_of('.');
        if(dotPos == string::npos)
        {
            *error = -5;
            return nullptr;
        }

        string s1 = param.inputFileName.substr(dotPos);
        const char *type = s1.c_str();

        if (strcasecmp(type, ".bmp") && strcasecmp(type, ".png") &&
            strcasecmp(type, ".jpg") && strcasecmp(type, ".jpeg")) // 所有格式都不符合
        {
            *error = -5;
            return nullptr;
        }
    }

    if (param.outFileName == "") // 未指定输出图像
    {
        int dirEndPos = param.inputFileName.find_last_of('/');
        if (dirEndPos == string::npos)
            dirEndPos = 0;
        else
            dirEndPos++;
        int dotPos = param.inputFileName.find_last_of('.');

        param.outFileName = param.inputFileName.substr(dirEndPos, dotPos - dirEndPos);
        param.outFileName += param.outFile ? ".bin" : ".c";
    }
    else // 截取指定的输出路径和文件名
    {
        int dirEndPos = param.outFileName.find_last_of('/');
        if (dirEndPos != string::npos)
        {
            param.outPath = param.outFileName.substr(0, dirEndPos + 1);
        }
        else
            param.outPath = "";        //当前路径

        int pathLen = param.outPath.length();
        param.outFileName = param.outFileName.substr(pathLen);       //减去路径

        if(param.outFileName == "")     //减去路径后若为空
        {
            *error = -1;
            return nullptr;
        }
    }

    if(param.outPath == "")
        param.outPath = "./";        //输入的文件名不带路径，则输出目录为当前目录

    *error = 0;

    printf("*******************conver param*******************\n");
    printf("param.imgcfg = %s\n", imgcfgString[param.imgcfg]);
    printf("param.format = %s\n", formats[param.format]);
    printf("param.outFile = %s\n", outfileString[param.outFile]);
    printf("param.inputFileName = %s\n", param.inputFileName.c_str());
    printf("param.outPath = %s\n", param.outPath.c_str());
    printf("param.outFileName = %s\n", param.outFileName.c_str());
    printf("*******************conver param*******************\n");

    return &param;
}

const char *ParamErrorToString(int error)
{
    error = abs(error);

    if (error > memberof(errorString))
        return nullptr;

    return errorString[error];
}

/**
 * @brief 判断是否是合法的转换格式
 * @retval 非负值 - 合法,且数值为格式索引
 * @retval -1 - 非法
 */
static int isLegalFormat(const char *format)
{
    for (int i = 0; i < memberof(formats); i++)
    {
        if (strcmp(format, formats[i]) == 0)
            return i;
    }

    return -1;
}

const char *helpInfo = "\
\
lv_img_conv: version 0.1\n\
\t-o\t指定输出文件名, 若输出为C文件, 则还作为变量名(变量名不包括后缀)\n\
\t\t\t若不指定该参数则以输入图像文件名代替(不包含后缀)\n\
\t\t\t此选项还可以指定输出路径,例:\"../src/img.bin\"\n\
\t-i\t指定输入图像(必要参数)\n\
\t-f\t指定转换格式,若使用\"-c\"转为C文件,则此选项不起作用(因为全部转换)\n\
\t\t\t可用的转换格式:[rgb332, rgb565, rgb565swap, rgb888(默认值)]\n\
\t-c\t输出为C文件(数组), 与\"-b\"互斥(默认参数)\n\
\t-b\t输出为bin文件, 与\"-c\"互斥\n\
\t--alpha\t添加alpha通道(可选, 但仅png文件有真实的alpha,其余均为0xff)\n\
\t--chromakey\t转换为CHROMA格式\n\
\
";
